package com.android.util;


import com.mp.chart.data.KLineData;
import com.mp.chart.data.MinutesData;
import com.mp.chart.model.ADX;
import com.mp.chart.model.ATR;
import com.mp.chart.model.KDJ;
import com.mp.chart.model.MACD;
import com.mp.chart.model.RSI;
import com.mp.chart.model.VOL;
import com.tictactec.ta.lib.Core;
import com.tictactec.ta.lib.MAType;
import com.tictactec.ta.lib.MInteger;
import com.tictactec.ta.lib.RetCode;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;


public class HqUtils {


    public static final List<MACD> getMACD(final List<KLineData> list, int macd1, int macd2, int macd3) {

        List<MACD> stickEntityList = new ArrayList<MACD>();
        int size = list.size();
        double close[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = list.get(i);
            close[i] = ohlcEntity.close;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double macdReturn[] = new double[close.length];
        double signal[] = new double[close.length];
        double hist[] = new double[close.length];
        RetCode retCode = lib.macd(0, close.length - 1, close, macd1, macd2, macd3,
                outBegIdx, outNbElement, macdReturn, signal, hist);
        if (RetCode.Success == retCode) {
            double realMacd[] = new double[close.length];
            double realSignal[] = new double[close.length];
            double realHist[] = new double[close.length];
            for (int i = 0; i < outNbElement.value; i++) {
                realMacd[outBegIdx.value + i] = macdReturn[i];
                realSignal[outBegIdx.value + i] = signal[i];
                realHist[outBegIdx.value + i] = hist[i];
            }
            for (int i = 0; i < realMacd.length; i++) {

                MACD m = new MACD();
                m.date = date[i];
                m.dea = getDecimal((float) (realSignal[i] * 1000000), 4) / 1000000;
                m.dif = getDecimal((float) (realMacd[i] * 1000000), 4) / 1000000;
                m.macd = getDecimal((float) (realHist[i] * 2 * 1000000), 4) / 1000000;
                stickEntityList.add(m);
            }
        }

        return stickEntityList;
    }

    public static float getDecimal(double num, int newScale) {
        if (Double.isNaN(num) || num == 0) {
            return Float.NaN;
        }
        BigDecimal bd = new BigDecimal(num);
        num = bd.setScale(newScale, BigDecimal.ROUND_HALF_UP).floatValue();
        return (float) num;
    }


    public static final List<KDJ> getKDJ(
            final List<KLineData> list, int k, int d, int j) {
        List<KDJ> kdjList = new ArrayList<KDJ>();
        int size = list.size();
        double close[] = new double[size];
        double high[] = new double[size];
        double low[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = (KLineData) list.get(i);
            close[i] = ohlcEntity.close;
            high[i] = ohlcEntity.high;
            low[i] = ohlcEntity.low;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double outK[] = new double[close.length];
        double outD[] = new double[close.length];
        RetCode retCode = lib.stoch(0, close.length - 1, high, low, close, k,
                d, MAType.Ema, j, MAType.Ema, outBegIdx, outNbElement, outK,
                outD);

        double realK[] = new double[close.length];
        for (int i = 0; i < outNbElement.value; i++) {
            realK[outBegIdx.value + i] = outK[i];
        }
        double realD[] = new double[close.length];
        for (int i = 0; i < outNbElement.value; i++) {
            realD[outBegIdx.value + i] = outD[i];
        }
        if (RetCode.Success == retCode) {

            for (int i = 0; i < realK.length; i++) {
                KDJ kdj = new KDJ();
                kdj.k = getDoubleFloat(realK[i]);
                kdj.d = getDoubleFloat(realD[i]);
                kdj.j = getDoubleFloat(3 * realK[i] - 2 * realD[i]);
                kdj.date = date[i];
                kdjList.add(kdj);
            }
        }

        return kdjList;
    }

    public static float getDoubleFloat(double num) {
        if (Double.isNaN(num) || num == 0) {
            return Float.NaN;
        }
        return (float) num;
    }

    public static final List<ATR> getAtr(
            final List<KLineData> list, int optInTimePeriod) {

        List<ATR> MAValues = new ArrayList<ATR>();
        int size = list.size();
        double close[] = new double[size];
        double high[] = new double[size];
        double low[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = (KLineData) list.get(i);
            close[i] = ohlcEntity.close;
            high[i] = ohlcEntity.high;
            low[i] = ohlcEntity.low;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double outReturn[] = new double[close.length];
        RetCode retCode = lib.atr(0, close.length - 1, high, low, close,
                optInTimePeriod, outBegIdx, outNbElement, outReturn);
        double outReal[] = new double[close.length];
        for (int i = 0; i < outNbElement.value; i++) {
            outReal[outBegIdx.value + i] = outReturn[i];
        }
        if (RetCode.Success == retCode) {
            for (int i = 0; i < outReal.length; i++) {
                ATR atr = new ATR();
                atr.date = date[i];
                atr.atr = getDoubleFloat(outReal[i]);
                MAValues.add(atr);
            }
        }
        return MAValues;
    }

    public static final List<ADX> getAdx(
            final List<KLineData> list, int optInTimePeriod) {

        List<ADX> MAValues = new ArrayList<ADX>();
        int size = list.size();
        double close[] = new double[size];
        double high[] = new double[size];
        double low[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = (KLineData) list.get(i);
            close[i] = ohlcEntity.close;
            high[i] = ohlcEntity.high;
            low[i] = ohlcEntity.low;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double outReturn[] = new double[close.length];
        RetCode retCode = lib.adx(0, close.length - 1, high, low, close,
                optInTimePeriod, outBegIdx, outNbElement, outReturn);
        double outReal[] = new double[close.length];
        for (int i = 0; i < outNbElement.value; i++) {
            outReal[outBegIdx.value + i] = outReturn[i];
        }
        if (RetCode.Success == retCode) {
            for (int i = 0; i < outReal.length; i++) {
                ADX adx = new ADX();
                adx.date = date[i];
                adx.adx = getDoubleFloat(outReal[i]);
                MAValues.add(adx);
            }
        }
        return MAValues;
    }

    public static final List<RSI> getRsi(
            final List<KLineData> list, final int days) {
        List<RSI> MAValues = new ArrayList<>();

        int size = list.size();
        double close[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = (KLineData) list.get(i);
            close[i] = ohlcEntity.close;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double outReturn[] = new double[close.length];
        RetCode retCode = RetCode.BadParam;
        retCode = lib.rsi(0, close.length - 1, close, days, outBegIdx,
                outNbElement, outReturn);
        double outReal[] = new double[close.length];
        for (int i = 0; i < outNbElement.value; i++) {
            outReal[outBegIdx.value + i] = outReturn[i];
        }
        if (RetCode.Success == retCode) {
            for (int i = 0; i < outReal.length; i++) {
                RSI rsi = new RSI();
                rsi.date = date[i];
                rsi.rsi1 = getDoubleFloat(outReal[i]);
                MAValues.add(rsi);
            }
        }
        return MAValues;
    }

    public static final List<RSI> getRsi(
            final List<KLineData> list, final int r1, final int r2, final int r3) {
        List<RSI> MAValues = new ArrayList<>();

        int size = list.size();
        double close[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = (KLineData) list.get(i);
            close[i] = ohlcEntity.close;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdxR1 = new MInteger();
        MInteger outBegIdxR2 = new MInteger();
        MInteger outBegIdxR3 = new MInteger();
        MInteger outNbElementR1 = new MInteger();
        MInteger outNbElementR2 = new MInteger();
        MInteger outNbElementR3 = new MInteger();
        double outReturnR1[] = new double[close.length];
        double outReturnR2[] = new double[close.length];
        double outReturnR3[] = new double[close.length];
        RetCode r1Code = lib.rsi(0, close.length - 1, close, r1, outBegIdxR1,
                outNbElementR1, outReturnR1);
        RetCode r2Code = lib.rsi(0, close.length - 1, close, r2, outBegIdxR2,
                outNbElementR2, outReturnR2);
        RetCode r3Code = lib.rsi(0, close.length - 1, close, r3, outBegIdxR3,
                outNbElementR3, outReturnR3);
        double outRealR1[] = new double[close.length];
        double outRealR2[] = new double[close.length];
        double outRealR3[] = new double[close.length];
        for (int i = 0; i < outNbElementR1.value; i++) {
            outRealR1[outBegIdxR1.value + i] = outReturnR1[i];
        }
        for (int i = 0; i < outNbElementR2.value; i++) {
            outRealR2[outBegIdxR2.value + i] = outReturnR2[i];
        }
        for (int i = 0; i < outNbElementR3.value; i++) {
            outRealR3[outBegIdxR3.value + i] = outReturnR3[i];
        }
        if (RetCode.Success == r1Code && RetCode.Success == r2Code && RetCode.Success == r3Code) {
            for (int i = 0; i < outRealR1.length; i++) {
                RSI rsi = new RSI();
                rsi.date = date[i];
                rsi.rsi1 = getDoubleFloat(outRealR1[i]);
                rsi.rsi2 = getDoubleFloat(outRealR2[i]);
                rsi.rsi3 = getDoubleFloat(outRealR3[i]);
                MAValues.add(rsi);
            }
        }

        return MAValues;
    }

    public static final ArrayList<KLineData> getmovingAverage(
            final ArrayList<KLineData> list, int type, int sumType, final int days) {
        //List<DateValueEntity> MAValues = new ArrayList<DateValueEntity>();
        ArrayList<Double> maDoubleList = new ArrayList<>();
        int size = list.size();
        double close[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {

            KLineData ohlcEntity = (KLineData) list.get(i);
            date[i] = ohlcEntity.date;
            switch (type) {
                case 0:
                    close[i] = ohlcEntity.open;
                    break;
                case 1:
                    close[i] = ohlcEntity.high;
                    break;
                case 2:
                    break;
                case 3:
                    close[i] = ohlcEntity.close;
                    break;
                case 4:
                    close[i] = ohlcEntity.low;
                    break;
            }
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double outReturn[] = new double[close.length];
        RetCode retCode5 = null;
        RetCode retCode10 = null;
        RetCode retCode30 = null;
        switch (sumType) {
            case 0:
                if (days == HqDefaultValue.MA1)
                    retCode5 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA1,
                            MAType.Sma, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA2)
                    retCode10 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA2,
                            MAType.Sma, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA3)
                    retCode30 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA3,
                            MAType.Sma, outBegIdx, outNbElement, outReturn);
                break;
            case 1:
                if (days == HqDefaultValue.MA1)
                    retCode5 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA1,
                            MAType.Ema, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA2)
                    retCode10 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA2,
                            MAType.Ema, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA3)
                    retCode30 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA3,
                            MAType.Ema, outBegIdx, outNbElement, outReturn);
            /*	retCode = lib.movingAverage(0, close.length - 1, close, days,
                        MAType.Ema, outBegIdx, outNbElement, outReturn);*/
                break;
            case 2:
                if (days == HqDefaultValue.MA1)
                    retCode5 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA1,
                            MAType.Wma, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA2)
                    retCode10 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA2,
                            MAType.Wma, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA3)
                    retCode30 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA3,
                            MAType.Wma, outBegIdx, outNbElement, outReturn);
            /*	retCode = lib.movingAverage(0, close.length - 1, close, days,
                        MAType.Wma, outBegIdx, outNbElement, outReturn);*/
                break;
            case 3:
                if (days == HqDefaultValue.MA1)
                    retCode5 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA1,
                            MAType.Trima, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA2)
                    retCode10 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA2,
                            MAType.Trima, outBegIdx, outNbElement, outReturn);
                else if (days == HqDefaultValue.MA3)
                    retCode30 = lib.movingAverage(0, close.length - 1, close, HqDefaultValue.MA3,
                            MAType.Trima, outBegIdx, outNbElement, outReturn);
				/*retCode = lib.movingAverage(0, close.length - 1, close, days,
						MAType.Trima, outBegIdx, outNbElement, outReturn);*/
                break;
        }
        double outReal[] = new double[close.length];
        for (int i = 0; i < outNbElement.value; i++) {
            outReal[outBegIdx.value + i] = outReturn[i];
        }
        if (RetCode.Success == retCode5) {
            for (int i = 0; i < outReal.length; i++) {
                if (outReal[i] == 0.0)
                    continue;
                list.get(i).ma5 = (float) outReal[i];
            }
        }
        if (RetCode.Success == retCode10) {
            for (int i = 0; i < outReal.length; i++) {
                if (outReal[i] == 0.0)
                    continue;
                list.get(i).ma10 = (float) outReal[i];
            }
        }
        if (RetCode.Success == retCode30) {
            for (int i = 0; i < outReal.length; i++) {
                if (outReal[i] == 0.0)
                    continue;
                list.get(i).ma30 = (float) outReal[i];
            }
        }
	/*	if (RetCode.Success == retCode) {
			for (int i = 0; i < outReal.length; i++) {
				if(outReal[i]==0.0)
					continue;
				maDoubleList.add(outReal[i]);
				//list.get(i).ma5 = (float) outReal[i];
			}
			//MAValues.add(new DateValueEntity((float) outReal[i], date[i]));
			//}
		}*/
        return list;
    }


    public static final List<KLineData> getMaBOLL(
            final List<KLineData> list, int period, int cha) {

        int size = list.size();
        double close[] = new double[size];
        String date[] = new String[size];
        for (int i = 0; i < size; i++) {
            KLineData ohlcEntity = (KLineData) list.get(i);
            close[i] = ohlcEntity.close;
            date[i] = ohlcEntity.date;
        }
        Core lib = new Core();
        MInteger outBegIdx = new MInteger();
        MInteger outNbElement = new MInteger();
        double up[] = new double[close.length];
        double mid[] = new double[close.length];
        double low[] = new double[close.length];
        RetCode retCode = lib.bbands(0, close.length - 1, close, period, cha, cha,
                MAType.Sma, outBegIdx, outNbElement, up, mid, low);
        if (RetCode.Success == retCode) {
            // List<DateValueEntity> maUp = new ArrayList<DateValueEntity>();
            double realUp[] = new double[close.length];
            double realMid[] = new double[close.length];
            double realLow[] = new double[close.length];
            for (int i = 0; i < outNbElement.value; i++) {
                realUp[outBegIdx.value + i] = up[i];
                realMid[outBegIdx.value + i] = mid[i];
                realLow[outBegIdx.value + i] = low[i];
            }
            for (int i = 0; i < realUp.length; i++) {
                list.get(i).maUp = getDoubleFloat(realUp[i]);
                list.get(i).maMid = getDoubleFloat(realMid[i]);
                list.get(i).maLow = getDoubleFloat(realLow[i]);
            }

        }

        return list;
    }


    /*k线中柱状图数据全部存放在MinuteData中   算法后期进行优化*/
    public static final List<VOL> getVol(final List<MinutesData> list, int ma5, int ma10, int ma30) {
        List<VOL> volList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            VOL v = new VOL();
            v.ma5 = Float.NaN;
            v.ma10 = Float.NaN;
            v.ma30 = Float.NaN;
            if (i >= ma5 - 1) {
                float allVol = 0;
                for (int j = i; j >= (i - (ma5 - 1)); j--) {
                    MinutesData kLineData = list.get(j);
                    v.vol = kLineData.chengjiaoliang;
                    allVol += kLineData.chengjiaoliang;
                }
                v.ma5 = allVol / ma5;
            }
            if (i >= ma10 - 1) {
                float allVol = 0;
                for (int j = i; j >= (i - (ma10 - 1)); j--) {
                    MinutesData kLineData = list.get(j);
                    v.vol = kLineData.chengjiaoliang;
                    allVol += kLineData.chengjiaoliang;
                }
                v.ma10 = allVol / ma10;
            }
            if (i >= ma30 - 1) {
                float allVol = 0;
                for (int j = i; j >= (i - (ma30 - 1)); j--) {
                    MinutesData kLineData = list.get(j);
                    v.vol = kLineData.chengjiaoliang;
                    allVol += kLineData.chengjiaoliang;
                }
                v.ma30 = allVol / ma30;
            }
            volList.add(i, v);

        }
        return volList;
    }
}
